home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / ast_comp / gopher.lha / gopher1.01 / gopherd / waisgopher.c < prev    next >
C/C++ Source or Header  |  1992-05-29  |  17KB  |  688 lines

  1. /* Wais to gopher gateway code.
  2.  
  3.    Paul Lindner, March 1992
  4.    <lindner@boombox.micro.umn.edu>
  5. */
  6.  
  7. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  8.    No guarantees or restrictions.  See the readme file for the full standard
  9.    disclaimer.
  10.    
  11.    Brewster@think.com
  12. */
  13.  
  14. #if defined(WAISSEARCH)   /*** Only compile this if we have WAIS ***/
  15.  
  16. #include <ctype.h>
  17. #include <string.h>
  18. #include <ui.h>
  19. #include <docid.h>
  20.  
  21. #define MAIN
  22. #include "wais.h"
  23.  
  24. #define WAISSEARCH_DATE "Fri Sep 13 1991"
  25.  
  26. #include "gopherd.h"
  27.  
  28. /**** Needed by wais-8-b5... Ick... ***/
  29.  
  30. char *sdir=NULL;
  31. char *cdir=NULL;
  32.  
  33. /**** Used by something in the source reading routines. ***/
  34. void
  35. PrintStatus(str)
  36. char * str;
  37. {
  38.      return;
  39. }
  40.  
  41. void find_value(source, key, value, value_size)
  42. char *source, *key, *value;
  43. int value_size;
  44. {
  45.   char ch;
  46.   long position = 0;  /* position in value */
  47.   char *pos =strstr(source, key); /* address into source */
  48.  
  49.   value[0] = '\0';        /* initialize to nothing */
  50.  
  51.   if(NULL == pos)
  52.     return;
  53.  
  54.   pos = pos + strlen(key);
  55.   ch = *pos;
  56.   /* skip leading quotes and spaces */
  57.   while((ch == '\"') || (ch == ' ')) {
  58.     pos++; ch = *pos;
  59.   }
  60.   for(position = 0; pos < source + strlen(source); pos++){
  61.     if((ch = *pos) == ' ') {
  62.       value[position] = '\0';
  63.       return;
  64.     }
  65.     value[position] = ch;
  66.     position++;
  67.     if(position >= value_size){
  68.       value[value_size - 1] = '\0';
  69.       return;
  70.     }
  71.   }
  72.   value[position] = '\0';
  73. }
  74.  
  75. /****/
  76.  
  77. void ZapTabs(in)
  78.   char *in;
  79. {
  80.      /** replace tabs with a space... **/
  81.      while (*in != '\0') {
  82.       if (*in == '\t')
  83.            *in = ' ';
  84.       in ++;
  85.      }
  86. }
  87.  
  88. /*** Modified from ../ir/ui.c to add \r\n at the ends of the line... ***/
  89. void
  90. Mydisplay_text_record_completely(record,quote_string_quotes, sockfd)
  91.   WAISDocumentText *record;
  92.   boolean quote_string_quotes;
  93. {
  94.      long count;
  95.      long ch;
  96.      char output[512];
  97.      int outputptr = 0;
  98.  
  99.      for(count = 0; count < record->DocumentText->size; count++){
  100.       
  101.       ch = (unsigned char)record->DocumentText->bytes[count];
  102.       
  103.       if(27 == ch){
  104.            /* then we have an escape code */
  105.            /* if the next letter is '(' or ')', then ignore two letters */
  106.            if('(' == record->DocumentText->bytes[count + 1] ||
  107.           ')' == record->DocumentText->bytes[count + 1])
  108.             count += 1;             /* it is a term marker */
  109.            else count += 4;        /* it is a paragraph marker */
  110.       }
  111.       else if (ch == '\t') /* a TAB! */
  112.            output[outputptr++] = ch;
  113.       else if (isprint(ch)){
  114.            if(quote_string_quotes && ch == '"') {
  115.             output[outputptr++] = '/';
  116.             output[outputptr++] = '/';
  117.            }
  118.            output[outputptr++] = ch;
  119.       } 
  120.       else if (ch == '\n' || ch == '\r') {
  121.            output[outputptr++] = '\r';
  122.            output[outputptr++] = '\n';
  123.       }
  124.            
  125.       if (outputptr >500) {
  126.            output[outputptr++] = '\0';
  127.            writestring(sockfd, output);
  128.            outputptr = 0;
  129.       }
  130.      }
  131.  
  132.  
  133.      /*** Write out the rest of the buffer...  ***/
  134.  
  135.      output[outputptr++] = '\0';
  136.      writestring(sockfd, output);
  137. }
  138.  
  139.  
  140.  
  141. /* modified from Jonny G's version in ui/question.c */
  142. void showDiags(d)
  143.   diagnosticRecord **d;
  144. {
  145.      long i;
  146.      
  147.      for (i = 0; d[i] != NULL; i++) {
  148.       if (d[i]->ADDINFO != NULL) {
  149.            printf("Code: %s, %s\n", d[i]->DIAG, d[i] ->ADDINFO);
  150.       }
  151.      }
  152. }
  153.  
  154.  
  155.  
  156. int
  157. acceptable(foo)
  158.   char foo;
  159. {
  160.      if (foo == '\t' || foo == '\r' || foo == '\n' || foo == '\0')
  161.       return(0);
  162.      else if (!isprint(foo))
  163.       return(0);
  164.      else
  165.       return(1);
  166. }
  167.  
  168.  
  169. static char * hex = "0123456789ABCDEF";
  170.  
  171. /*
  172.  * DocId_to_Gopher transforms a docid into a character string suitable for
  173.  * transmission
  174.  */
  175.  
  176. char *DocId_to_Gopher(docid, docsize)
  177.   any *docid;
  178.   int docsize;
  179. {
  180.      static char GopherString[512];
  181.      char *q = GopherString;
  182.      char *p;
  183.      int l, i;
  184.           
  185.      /** First lets stick on the size of the document first **/
  186.  
  187.      sprintf(GopherString, "%d", docsize);
  188.      q += strlen(GopherString);
  189.      *q++ = ':';
  190.  
  191.      for (p=docid->bytes; (p < docid->bytes + docid->size) && q<&GopherString[512];) {
  192.       if (*p >= 10) {
  193.            ; /* Bad thing happened, can't understand docid, punt */
  194.            return(NULL);
  195.       }
  196.       
  197.       *q++ = (*p++) + '0';   /* Record Type */
  198.       *q++ = '=';            /* Seperate */
  199.       l = *p++;              /* Length */
  200.       for (i=0; i<l; i++, p++) {
  201.            if (acceptable(*p)==0) {
  202.             *q++ = '%';
  203.             *q++ = hex[(*p) >> 4];
  204.             *q++ = hex[(*p) & 15];
  205.            }
  206.            else *q++ = *p;
  207.       }
  208.       *q++ = ';';
  209.      }
  210.      *q++ = 0;
  211.      return(GopherString);
  212. }
  213.  
  214. /*
  215.  * Gstring is a name produced by DocID_to_Gopher
  216.  */
  217.  
  218. any *Gopher_to_DocId(Gstring, DocSize)
  219.   char *Gstring;
  220.   int *DocSize;
  221. {
  222.      static any docid;
  223.      char *outptr;
  224.      char *inptr; 
  225.      char *sor;
  226.      char *eqptr;  
  227.      char *semiptr;
  228.      int size; 
  229.  
  230.      /* Strip off the Document size first.... */
  231.      
  232.      inptr = strchr(Gstring, ':');
  233.      if (inptr == NULL) 
  234.       return;
  235.  
  236.      *DocSize = atoi(Gstring);
  237.      
  238.      Gstring = inptr +1;
  239.  
  240.      for (size=0, inptr=Gstring; *inptr; inptr++) {
  241.       size ++;
  242.       if (*inptr == ';') 
  243.            size--;
  244.       else if (*inptr ==  '%') 
  245.            size -=2;
  246.       
  247.      }
  248.  
  249.      docid.size = size;
  250.  
  251.      docid.bytes = (char *) malloc(docid.size);
  252.      outptr = docid.bytes;
  253.  
  254.      for (inptr = Gstring; *inptr;) {
  255.       *outptr++ = *inptr++ - '0';  /* Record Type */
  256.       eqptr = strchr(inptr, '=');
  257.       if (!eqptr)
  258.            return(0);
  259.       semiptr = strchr(inptr, ';');
  260.       if (!semiptr)
  261.            return(0);
  262.       sor = outptr;
  263.       outptr++;
  264.  
  265.       for (inptr = eqptr+1; *inptr!=';' ; ) {
  266.            if (*inptr == '%') {
  267.             char c;
  268.             unsigned int b;
  269.             
  270.             inptr++;
  271.             c = *inptr++;
  272.             b = from_hex(c);
  273.             c = *inptr++;
  274.             if (!c) break;
  275.             *outptr++ = (b<<4) + from_hex(c);
  276.            } else {
  277.             *outptr++ = *inptr++;
  278.            }
  279.       }
  280.       
  281.       *sor = (outptr-sor-1);
  282.       inptr++;
  283.      }
  284.      
  285.      return(&docid);
  286.  
  287. }
  288.             
  289.  
  290.  
  291. /*-----------------------------------------------------------------*/
  292.  
  293. /* modified from tracy shen's version in wutil.c
  294.  * displays either a text record of a set of headlines.
  295.  */
  296. void
  297. display_search_response(response, hostname, port, dbname, SourceName, sockfd)
  298.   SearchResponseAPDU *response;
  299.   char *hostname, *port, *dbname, *SourceName;
  300.   int sockfd;
  301. {
  302.      WAISSearchResponse  *info;
  303.      long i, k;
  304.      struct sockaddr_in serv_addr;
  305.      int length = sizeof(serv_addr);
  306.      GopherObj *gs = NULL;
  307.      GopherDirObj *gd = NULL;
  308.      char gopherpath[1024];
  309.  
  310.      gs = GSnew();
  311.      gd = GDnew(64);
  312.  
  313.      if ( response->DatabaseDiagnosticRecords != 0 ) {
  314.       info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
  315.       i =0; 
  316.           
  317.       if (info->Diagnostics != NULL)
  318.            showDiags(info->Diagnostics);
  319.       
  320.       if ( info->DocHeaders != 0 ) {
  321.            k =0;
  322.            while (info->DocHeaders[k] != 0 ) {
  323.             i++;
  324.             ZapCRLF(info->DocHeaders[k]->Headline);
  325.             ZapTabs(info->DocHeaders[k]->Headline);
  326.             
  327.             GSinit(gs);
  328.             GSsetType(gs, '0');
  329.             GSsetTitle(gs, info->DocHeaders[k]->Headline);
  330.             
  331.             sprintf(gopherpath, "waisdocid:%s:%s",
  332.                 SourceName, 
  333.                 DocId_to_Gopher(info->DocHeaders[k]->DocumentID,
  334.                         info->DocHeaders[k]->DocumentLength));
  335.             GSsetPath(gs, gopherpath);
  336.             GSsetHost(gs, Zehostname);
  337.             GSsetPort(gs, GopherPort);
  338.  
  339.             GDaddGS(gd, gs);
  340.             k++;
  341.            }
  342.            
  343.            GDtoNet(gd, sockfd);
  344.            writestring(sockfd, ".\r\n");
  345.       }
  346.  
  347.       if ( info->Text != 0 ) {
  348.            k =0;
  349.            while ((info->Text[k] != 0) ) {
  350.             i++;
  351.             printf("\n    Text record %2d, ", i);
  352.             Mydisplay_text_record_completely( info->Text[k++], false, sockfd);
  353.            }
  354.       }
  355.      }
  356. }
  357.  
  358.  
  359.  
  360. #define MAX_KEYWORDS_LENGTH 1000
  361. #define MAX_SERVER_LENGTH 1000
  362. #define MAX_DATABASE_LENGTH 1000
  363. #define MAX_SERVICE_LENGTH 1000
  364. #define MAXDOCS 40
  365.  
  366. /******************************************************************/
  367.  
  368. void SearchRemoteWAIS(sockfd, inputline)
  369.   int sockfd;
  370.   char *inputline;
  371. {
  372.      char* request_message = NULL; /* arbitrary message limit */
  373.      char* response_message = NULL; /* arbitrary message limit */
  374.      long request_buffer_length;    /* how of the request is left */
  375.      SearchResponseAPDU  *query_response;
  376.      SearchResponseAPDU  *retrieval_response;
  377.      WAISSearchResponse  *query_info, *retrieval_info;
  378.      char server_name[MAX_SERVER_LENGTH + 1];    
  379.      char service[MAX_SERVICE_LENGTH + 1];
  380.      char database[MAX_DATABASE_LENGTH + 1];
  381.      long count;
  382.      FILE *connection;
  383.      char *keywords;
  384.      FILE *Dotsrcfile;
  385.      char *SourceName;
  386.      char *WaisGatePort=NULL;
  387.      Source Moo;
  388.      char *cp;
  389.  
  390.  
  391.      server_name[0] = '\0';  /* null it out */
  392.      database[0] = '\0';     /* null it out */
  393.      service[0] = '\0';      /* null it out */
  394.  
  395.  
  396.      /**
  397.       ** Next load up the name of the source...
  398.       */
  399.      
  400.      cp = strchr(inputline, '\t');
  401.      keywords = cp + 1;
  402.      
  403.      if (cp == NULL) {
  404.       /** An error occured, probably old client software... **/
  405.       writestring(sockfd, ".\r\n");
  406.      } else
  407.       *cp = '\0';
  408.      
  409.      SourceName= inputline;
  410.      
  411.      Moo = (Source)malloc(sizeof(_Source));
  412.      
  413.      Dotsrcfile = rfopen(SourceName, "r");
  414.      if (Dotsrcfile == NULL) {
  415.       char tmpstr[256];
  416.       sprintf(tmpstr, "File '%s' does not exist", SourceName);
  417.       Abortoutput(sockfd, tmpstr), exit(-1);
  418.      }
  419.      
  420.      ReadSource(Moo, Dotsrcfile);
  421.      strcpy(server_name, Moo->server);
  422.      strcpy(database, Moo->database);
  423.      strcpy(service, Moo->service);
  424.      
  425.      if (server_name[0] == 0)
  426.       connection = NULL;
  427.      
  428.      else if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
  429.      {
  430.       char Errorstr[256];
  431.  
  432.       sprintf(Errorstr,"Error openning connection to %s via service %s.", 
  433.           server_name, service);
  434.       Abortoutput(sockfd, Errorstr);
  435.       exit(-1);
  436.      }
  437.      
  438.      request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  439.      response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  440.      {
  441.       char userInfo[256];
  442.  
  443.       sprintf(userInfo, "waisgopher %s, from host: %s", VERSION, Zehostname);
  444.       init_connection(request_message, response_message,
  445.               MAX_MESSAGE_LEN,
  446.               connection,
  447.               userInfo);
  448.      }
  449.      request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  450.      
  451.      if(NULL ==
  452.     generate_search_apdu(request_message + HEADER_LENGTH, 
  453.                  &request_buffer_length, 
  454.                  keywords, database, NULL, MAXDOCS))
  455.       Abortoutput(sockfd, "request too large");
  456.      
  457.      
  458.      if(0 ==
  459.     interpret_message(request_message, 
  460.               MAX_MESSAGE_LEN - request_buffer_length, 
  461.               response_message,
  462.               MAX_MESSAGE_LEN,
  463.               connection,
  464.               false    /* true verbose */
  465.               )) { /* perhaps the server shut down on us, let's see: */
  466.       if ( connection != NULL) {
  467.            fclose(connection);
  468.            if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
  469.            {
  470.             char Errorstr[256];
  471.  
  472.             sprintf(Errorstr, "Error openning connection to %s via service %s.\n",
  473.                server_name, service);
  474.             Abortoutput(sockfd, Errorstr);
  475.            }
  476.  
  477.            if(0 ==
  478.           interpret_message(request_message, 
  479.                     MAX_MESSAGE_LEN - request_buffer_length, 
  480.                     response_message,
  481.                     MAX_MESSAGE_LEN,
  482.                     connection,
  483.                     false /* true verbose */
  484.                     ))
  485.             Abortoutput(sockfd, "really couldn't deliver message");
  486.       }
  487.       else
  488.            Abortoutput("returned message too large");
  489.      }
  490.      
  491.      readSearchResponseAPDU(&query_response, response_message + HEADER_LENGTH);
  492.      
  493.      display_search_response(query_response, server_name, service, database, SourceName, sockfd);
  494.      
  495.      freeWAISSearchResponse(query_response->DatabaseDiagnosticRecords);         
  496.      freeSearchResponseAPDU( query_response);
  497.      
  498.      /*** close it down ***/
  499.      
  500.      close_connection(connection);
  501.      
  502.      s_free(request_message);
  503.      s_free(response_message);
  504.      
  505. }
  506.  
  507.  
  508.  
  509.  
  510. /*******************************************************/
  511.  
  512. void
  513. Fetchdocid(sockfd, inputline)
  514.   int sockfd;
  515.   char *inputline;
  516. {
  517.      any *docid;
  518.      int DocLen;
  519.      int count;
  520.      char* request_message = NULL; /* arbitrary message limit */
  521.      char* response_message = NULL; /* arbitrary message limit */
  522.      long request_buffer_length;    /* how of the request is left */
  523.      char server_name[MAX_SERVER_LENGTH + 1];    
  524.      char service[MAX_SERVICE_LENGTH + 1];
  525.      char database[MAX_DATABASE_LENGTH + 1];
  526.      SearchResponseAPDU  *retrieval_response;
  527.      FILE *connection;
  528.      char *SourceName;
  529.      char *WaisGatePort=NULL;
  530.      Source Moo;
  531.      char *DocIdString;
  532.      FILE *Dotsrcfile;
  533.  
  534.  
  535.      server_name[0] = '\0';  /* null it out */
  536.      database[0] = '\0';     /* null it out */
  537.      service[0] = '\0';      /* null it out */
  538.  
  539.  
  540.      DocIdString = strchr(inputline, ':');
  541.      if (DocIdString == NULL) {
  542.       Abortoutput(sockfd, "Malformed docid");
  543.       return;
  544.      }
  545.      else {
  546.       *DocIdString = '\0';
  547.       DocIdString++;
  548.      }
  549.  
  550.      SourceName = inputline;
  551.      
  552.      Moo = (Source)malloc(sizeof(_Source));
  553.      
  554.      Dotsrcfile = rfopen(SourceName, "r");
  555.      if (Dotsrcfile == NULL) {
  556.       char tempstr[256];
  557.  
  558.       sprintf(tempstr, "File '%s' does not exist", SourceName);
  559.       Abortoutput(sockfd, tempstr);
  560.       exit(-1);
  561.      }
  562.      
  563.      ReadSource(Moo, Dotsrcfile);
  564.      strcpy(server_name, Moo->server);
  565.      strcpy(database, Moo->database);
  566.      strcpy(service, Moo->service);
  567.      
  568.      if (server_name[0] == 0)
  569.       connection = NULL;
  570.  
  571.  
  572.      else if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
  573.      {
  574.       char Errorstr[256];
  575.  
  576.       sprintf(Errorstr,"Error openning connection to %s via service %s.", 
  577.           server_name, service);
  578.       Abortoutput(sockfd, Errorstr);
  579.       return;
  580.      }
  581.      request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  582.      response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  583.  
  584.      docid = Gopher_to_DocId(DocIdString, &DocLen);
  585.      
  586.      /*** First let's transform the first word into a docid ***/
  587.      /*** What we need from net:  DocumentLength, Types: (TEXT!), docid, **/
  588.      
  589.      for(count = 0; 
  590.      count * CHARS_PER_PAGE <
  591.      DocLen;
  592.      count++){
  593.       
  594.       char *type;
  595.       /*           if(query_info->DocHeaders[1]->Types == NULL)*/
  596.       type = s_strdup("TEXT");
  597.       /*           else
  598.                type = s_strdup(query_info->DocHeaders[1]->Types[0]);*/
  599.       request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  600.       if(0 ==
  601.          generate_retrieval_apdu(request_message + HEADER_LENGTH,
  602.                      &request_buffer_length, 
  603.                      docid, 
  604.                      CT_byte,
  605.                      count * CHARS_PER_PAGE,
  606.                      MIN((count + 1) * CHARS_PER_PAGE,
  607.                      DocLen),
  608.                      type,
  609.                      database
  610.                      ))
  611.            panic("request too long");
  612.       
  613.       if(0 ==
  614.          interpret_message(request_message, 
  615.                    MAX_MESSAGE_LEN - request_buffer_length, 
  616.                    response_message,
  617.                    MAX_MESSAGE_LEN,
  618.                    connection,
  619.                    false /* true verbose */    
  620.                    )) { /* perhaps the server shut down on us, let's see: */
  621.            if ( connection != NULL) {
  622.             fclose(connection);
  623.             if ((connection=connect_to_server(server_name,atoi(service))) == NULL) 
  624.             {
  625.              fprintf (stderr, "Error openning connection to %s via service %s.\n",
  626.                   server_name, service);
  627.              exit(-1);
  628.             }
  629.             if(0 ==
  630.                interpret_message(request_message, 
  631.                      MAX_MESSAGE_LEN - request_buffer_length, 
  632.                      response_message,
  633.                      MAX_MESSAGE_LEN,
  634.                      connection,
  635.                      false /* true verbose */
  636.                      ))
  637.              panic("really couldn't deliver message");
  638.            }
  639.            else
  640.             panic("returned message too large");
  641.       }
  642.       
  643.       readSearchResponseAPDU(&retrieval_response, 
  644.                  response_message + HEADER_LENGTH);
  645.       
  646.       /* display_search_response(retrieval_response); the general thing */
  647.       if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text){
  648.            display_search_response(retrieval_response);
  649.            panic("No text was returned");
  650.       }
  651.       Mydisplay_text_record_completely
  652.            (((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], false, sockfd);
  653.      }
  654.  
  655.      freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
  656.      freeSearchResponseAPDU( retrieval_response);
  657.  
  658.      /*** close it down ***/
  659.  
  660.      close_connection(connection);
  661.      
  662.      s_free(request_message);
  663.      s_free(response_message);
  664.  
  665.      writestring(sockfd, ".\r\n");
  666. }
  667.  
  668. #else /* defined(WAISSEARCH) */
  669.  
  670. void
  671. SearchRemoteWAIS(sockfd, selstr)
  672.   int sockfd;
  673.   char *selstr;
  674. {
  675.      Abortoutput(sockfd, "No wais stuff in the server!!");
  676. }
  677.  
  678.  
  679. void
  680. Fetchdocid(sockfd, selstr)
  681.   int sockfd;
  682.   char *selstr;
  683. {
  684.      Abortoutput(sockfd, "No wais stuff in the server!!");
  685. }
  686.  
  687. #endif
  688.